package com.qipay.pay.impl;

import com.qipay.baas.model.CpChannel;
import com.qipay.baas.model.Order;
import com.qipay.cp.CpService;
import com.qipay.cpchannel.service.CpChannelService;
import com.qipay.order.config.OrderSettleStateEnum;
import com.qipay.order.config.OrderStateEnum;
import com.qipay.order.service.OrderService;
import com.qipay.pay.WeiXinMpPayService;
import com.qipay.pay.entity.CpPayWeiXinMpPayRequest;
import com.qipay.scalar.type.ChannelTypeEnum;
import com.qipay.security.jwt.JWTUser;
import com.qipay.sp.SpApiConfigService;
import com.qipay.sp.SpChannelService;
import com.qipay.sp.SpService;
import com.qipay.sp.excutor.ExcutorFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Service
public class WeiXinMpPayServiceImpl implements WeiXinMpPayService {

    protected final Log logger = LogFactory.getLog(this.getClass());

    @Autowired
    OrderService orderService;

    @Autowired
    CpService cpService;

    @Autowired
    CpChannelService cpChannelService;

    @Autowired
    SpChannelService spChannelService;

    @Autowired
    SpApiConfigService spApiConfigService;

    @Autowired
    SpService spService;

    @Value("${api.response.sign.name}")
    String apiResponseSignName;

    @Value("${api.response.key.name}")
    String apiResponseKeyName;

    @Transactional
    @Override
    public Order jspayCreateOrder(CpPayWeiXinMpPayRequest entity,
            JWTUser loggedUser) throws Exception {

        Assert.notNull(loggedUser, "找不到登录信息");
        Assert.notNull(entity, "请输入交易信息");
        Assert.notNull(entity.getBody(), "请输入商品描述");
        Assert.notNull(entity.getMchId(), "请输入商户号");
        Assert.isTrue(StringUtils.equals(entity.getMchId(), loggedUser.getUsername())
                , "输入的商户号与登录信息不一致");
        Assert.notNull(entity.getOutTradeNo(), "请输入CP订单号");
        Assert.notNull(entity.getTotalFee(), "请输入总金额");
        Assert.isTrue(entity.getTotalFee() > 0, "总金额必须大于0");
        Assert.notNull(entity.getMchCreateIp(), "请输入订单生成的机器 IP");
        Assert.notNull(entity.getNotifyUrl(), "请输入notify_url");
        Assert.notNull(entity.getNonceStr(), "请输入nonce_str");

//        Assert.isTrue(cpService.isIPValid(loggedUser.getId(), entity.getMchCreateIp())
//                , "非法ip值");

        CpChannel cpChannel = cpChannelService.getByCpIdAndChannelType(loggedUser.getId(),
                ChannelTypeEnum.WX_MP.getType());
        Assert.notNull(cpChannel, "该CP没有开通微信公众号服务");
        Assert.isTrue(cpChannel.getState() == 0, "该CP的微信公众号服务已经被禁用");
        Assert.notNull(cpChannel.getFeeRecharge(), "该CP没有配置费率");
        Assert.notNull(cpChannel.getRateAdvince(), "该CP没有配置到账比率");

        Order order = orderService.getByCpidAndOutTradeNo(loggedUser.getId(), entity.getOutTradeNo());
        if (order != null) {
            Assert.isTrue(Objects.equals(OrderStateEnum.NOTPAY.getType(), order.getState()),
                    "无效的订单状态:" + OrderStateEnum.getByType(order.getState()).getInfo());
        } else {
            order = new Order();
            order.setCpId(loggedUser.getId());
            order.setChannelType(ChannelTypeEnum.WX_MP.getType());
            order.setBody(entity.getBody());
            order.setAmount(entity.getTotalFee());
            order.setFeeRecharge(cpChannel.getFeeRecharge());
            order.setState(OrderStateEnum.NOTPAY.getType());
            order.setTradeNo(orderService.createOrder());
            order.setOutTradeNo(entity.getOutTradeNo());
            order.setNotifyUrl(entity.getNotifyUrl());
            order.setAttach(entity.getAttach());
            order.setCreateTime(new Date());
            order.setSettleStatus(OrderSettleStateEnum.NOTSETTLE.getType());


            order.setFee(cpChannel.getFeeRecharge().multiply(
                    new BigDecimal(entity.getTotalFee().toString())).intValue());
            order.setActualAmount(order.getAmount() - order.getFee());
            order.setAdvanceAmount(cpChannel.getRateAdvince().multiply(
                    new BigDecimal(order.getActualAmount().toString())).intValue());
            order.setDisableAmount(order.getActualAmount() - order.getAdvanceAmount());

            CpChannel agentChannel = cpChannelService.getAgentChannel(cpChannel);
            if(agentChannel != null) {
                order.setAgentId(agentChannel.getCpId());
                order.setAgentFeeRecharge(agentChannel.getFeeRecharge());
                order.setAgentFee(agentChannel.getFeeRecharge().multiply(
                        new BigDecimal(entity.getTotalFee().toString())
                ).intValue());
            }

            order = orderService.selectASp(order, ChannelTypeEnum.WX_MP);

            orderService.insert(order);

            if(order.getId() == null || order.getId() == 0) {
                logger.error("订单信息无法入库，order.id:" + order.getId());
                throw new Exception("无法生成订单");
            }
        }
        return order;
    }

    @Transactional
    @Override
    public Map<String, Object> jspay(Long orderId, String openId) throws Exception {

        Assert.notNull(openId, "找不到登录信息");
        Assert.notNull(orderId, "请输入交易信息");

        Order order = orderService.get(orderId);
        Assert.notNull(order, "请输入交易信息");
        Assert.isTrue(Objects.equals(OrderStateEnum.NOTPAY.getType(), order.getState()),
                "无效的订单状态:" + OrderStateEnum.getByType(order.getState()).getInfo());


        Map<String, Object> extendOrderParams = new HashMap<>();
        extendOrderParams.put("sub_openid", openId);

        ExcutorFactory excutorFactory = spService.getFactory(order.getSpId());
        return excutorFactory.createWxMpPayExcutor().excutor(order, extendOrderParams);
    }
}
